/*
	Copyright (C) 2010 Salil Bhagurkar

	This file is part of k3

	k3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	k3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with k3.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <shared.h>

/*Execution system of k3 that will run the file system (!!)*/

/**
 * This function is used by the runner to transfer data
 * based on the links. It does not allow data transfer to
 * write data into a constant node.
 */
static int fsrun_transfer_data(struct fs *fs1, struct fs *fs0)
{
	dprint(D_INFO, "", "%s to %s", fs0->name, fs1->name);
	struct buffer *buffer = buffer_create(0);
	//Perform read on the source node
	fs_read(fs1, fs0, buffer, 0, fs0->buf.len);
	if(buffer->len == 0) {
		dprint(D_ALERT, fs0->name, "Length is zero post read");
	}
	//Now use the read amount (indicated in the buffer structure)
	//to write back to the destination node
	fs_write(fs0, fs1, buffer, 0, buffer->len);

	buffer_free(buffer);
	return 0;
}

/**
 * Function that runs the file system to read and write data
 * Nodes marked with mode as R are read from and those with W
 * are written to
 */
static int fsrun_main(struct fs *start)
{
	struct fs *child;
	int err;
	u32 type;
	type = start->flags & FSFLAGS_TYPE_MASK;
	{
		dprint(D_INFO, start->name, "");
		child = start;
		err = fsiter_get_child(&child);
		if(err) //No children i guess
			return 0;
		while(!err) {
			//Determine the transfer direction from the child mode
			u32 child_mode = child->flags & FSFLAGS_MODE_MASK;
			if(child_mode == FSFLAGS_MODE_READ) {
				dprint(D_INFO, child->name, "get data (mode = %u)", child_mode);
				fsrun_main(child);
				err = fsrun_transfer_data(start, child);
				if(err) {
					dprint(D_ALERT, child->name, "transfer failure (code = %d)", err);
				}
			}
			err = fsiter_get_next(&child);
		}
		child = start;
		err = fsiter_get_child(&child);
		if(err) //No children i guess
			return 0;
		while(!err) {
			//Determine the transfer direction from the child mode
			u32 child_mode = child->flags & FSFLAGS_MODE_MASK;
			if(child_mode == FSFLAGS_MODE_WRITE) {
				dprint(D_INFO, child->name, "give data (mode = %u)", child_mode);
				err = fsrun_transfer_data(child, start);
				if(err) {
					dprint(D_ALERT, child->name, "transfer failure (code = %d)", err);
				}
				fsrun_main(child);
			}
			err = fsiter_get_next(&child);
		}
		child = start;
		err = fsiter_get_child(&child);
		if(err) //No children i guess
			return 0;
		while(!err) {
			//Determine the transfer direction from the child mode
			u32 child_mode = child->flags & FSFLAGS_MODE_MASK;
			if(child_mode == 0) {
				dprint(D_INFO, child->name, "move to");
				fsrun_main(child);
			}
			err = fsiter_get_next(&child);
		}
	}
	return 0;
}

int fsrun(struct fs *start_fs)
{
	if(!start_fs)
		return EPINV;
	fsrun_main(start_fs);
	return 0;
}
